#!/usr/bin/env python3
"""
任务 4: 创建目录扫描器核心功能
文件: utils/directory_scanner.py
实现 scan_directory() 函数递归扫描目录
实现 find_git_repositories() 函数查找所有 .git 目录
实现 is_valid_git_repo() 函数验证 Git 仓库
"""

import os
import pathlib
from typing import List, Set
from datetime import datetime

class DirectoryScanner:
    """目录扫描器"""
    
    def __init__(self, max_depth: int = 10):
        """
        初始化目录扫描器
        
        Args:
            max_depth: 最大扫描深度
        """
        self.max_depth = max_depth
        self.scanned_count = 0
        self.git_repos_found = 0
    
    def scan_directory(self, root_directory: str, 
                      include_patterns: List[str] = None,
                      exclude_patterns: List[str] = None) -> List[str]:
        """
        递归扫描目录，查找所有 Git 仓库
        
        Args:
            root_directory: 根目录路径
            include_patterns: 包含的路径模式列表
            exclude_patterns: 排除的路径模式列表
            
        Returns:
            List[str]: 找到的 Git 仓库路径列表
        """
        import fnmatch
        
        self.scanned_count = 0
        self.git_repos_found = 0
        git_repos = []
        
        print(f"开始扫描目录: {root_directory}")
        start_time = datetime.now()
        
        try:
            # 验证根目录
            root_path = pathlib.Path(root_directory)
            if not root_path.exists():
                print(f"错误：根目录不存在: {root_directory}")
                return git_repos
            
            if not root_path.is_dir():
                print(f"错误：路径不是目录: {root_directory}")
                return git_repos
            
            # 递归扫描目录
            git_repos = self._scan_recursive(
                root_path, 
                0, 
                include_patterns, 
                exclude_patterns
            )
            
            end_time = datetime.now()
            duration = (end_time - start_time).total_seconds()
            
            print(f"扫描完成: 扫描了 {self.scanned_count} 个目录，"
                  f"找到 {self.git_repos_found} 个 Git 仓库，"
                  f"耗时 {duration:.2f} 秒")
            
            return git_repos
            
        except Exception as e:
            print(f"扫描目录时发生错误: {str(e)}")
            return git_repos
    
    def _scan_recursive(self, current_path: pathlib.Path, 
                       current_depth: int,
                       include_patterns: List[str] = None,
                       exclude_patterns: List[str] = None) -> List[str]:
        """
        递归扫描目录（内部方法）
        
        Args:
            current_path: 当前路径
            current_depth: 当前深度
            include_patterns: 包含的路径模式列表
            exclude_patterns: 排除的路径模式列表
            
        Returns:
            List[str]: 在此路径下找到的 Git 仓库列表
        """
        import fnmatch
        
        git_repos = []
        
        # 检查深度限制
        if current_depth > self.max_depth:
            return git_repos
        
        # 检查是否应该排除此路径
        if exclude_patterns and self._should_exclude_path(current_path, exclude_patterns):
            return git_repos
        
        # 检查是否应该包含此路径
        if include_patterns and not self._should_include_path(current_path, include_patterns):
            return git_repos
        
        # 扫描当前目录
        try:
            for item in current_path.iterdir():
                if item.is_dir():
                    self.scanned_count += 1
                    
                    # 检查是否为 Git 仓库
                    if self._is_valid_git_repo(str(item)):
                        git_repos.append(str(item))
                        self.git_repos_found += 1
                        print(f"  发现 Git 仓库: {item}")
                    else:
                        # 递归扫描子目录
                        child_repos = self._scan_recursive(
                            item, 
                            current_depth + 1,
                            include_patterns,
                            exclude_patterns
                        )
                        git_repos.extend(child_repos)
                        
        except PermissionError:
            print(f"  权限不足，跳过目录: {current_path}")
        except Exception as e:
            print(f"  扫描目录时发生错误: {current_path} - {str(e)}")
        
        return git_repos
    
    def find_git_repositories(self, directory: str, 
                            include_patterns: List[str] = None,
                            exclude_patterns: List[str] = None) -> List[str]:
        """
        查找指定目录中的所有 Git 仓库
        
        Args:
            directory: 要搜索的目录
            include_patterns: 包含的路径模式列表
            exclude_patterns: 排除的路径模式列表
            
        Returns:
            List[str]: 找到的 Git 仓库路径列表
        """
        return self.scan_directory(directory, include_patterns, exclude_patterns)
    
    def is_valid_git_repo(self, path: str) -> bool:
        """
        验证是否为有效的 Git 仓库
        
        Args:
            path: 仓库路径
            
        Returns:
            bool: 是否为有效的 Git 仓库
        """
        try:
            repo_path = pathlib.Path(path)
            
            # 检查路径是否存在且为目录
            if not repo_path.exists() or not repo_path.is_dir():
                return False
            
            # 检查是否存在 .git 目录
            git_dir = repo_path / ".git"
            if not git_dir.exists():
                return False
            
            # 检查 .git 是否为目录（对于子模块可能是文件）
            if git_dir.is_file():
                # 对于子模块，.git 是一个文件，包含 gitdir 路径
                try:
                    with open(git_dir, 'r') as f:
                        content = f.read().strip()
                        if content.startswith("gitdir: "):
                            return True
                except:
                    return False
            elif git_dir.is_dir():
                # 对于普通仓库，.git 是一个目录
                return True
            
            return False
            
        except Exception:
            return False
    
    def _should_include_path(self, path: pathlib.Path, patterns: List[str]) -> bool:
        """
        检查路径是否应该被包含
        
        Args:
            path: 路径对象
            patterns: 包含模式列表
            
        Returns:
            bool: 是否应该包含
        """
        import fnmatch
        
        path_str = str(path)
        for pattern in patterns:
            if fnmatch.fnmatch(path_str, pattern):
                return True
        return True  # 如果没有包含模式，默认包含
    
    def _should_exclude_path(self, path: pathlib.Path, patterns: List[str]) -> bool:
        """
        检查路径是否应该被排除
        
        Args:
            path: 路径对象
            patterns: 排除模式列表
            
        Returns:
            bool: 是否应该排除
        """
        import fnmatch
        
        path_str = str(path)
        for pattern in patterns:
            if fnmatch.fnmatch(path_str, pattern):
                return True
        return False

def test_directory_scanner():
    """测试目录扫描器"""
    print("测试目录扫描器...")
    
    scanner = DirectoryScanner(max_depth=5)
    
    # 测试扫描当前目录
    current_dir = "."
    print(f"扫描当前目录: {current_dir}")
    git_repos = scanner.find_git_repositories(current_dir)
    print(f"找到的 Git 仓库: {git_repos}")
    
    # 测试包含/排除模式
    include_patterns = ["*"]  # 包含所有
    exclude_patterns = ["*/.git", "*/venv", "*/node_modules"]
    
    print(f"包含模式: {include_patterns}")
    print(f"排除模式: {exclude_patterns}")
    
    filtered_repos = scanner.find_git_repositories(
        current_dir, 
        include_patterns, 
        exclude_patterns
    )
    print(f"过滤后的 Git 仓库: {filtered_repos}")
    
    # 测试无效路径
    invalid_repos = scanner.find_git_repositories("/nonexistent/path")
    print(f"无效路径测试结果: {invalid_repos}")

if __name__ == "__main__":
    test_directory_scanner()